#pragma once

#include <vector>
#include <queue>
#include <mutex>
#include <semaphore.h>

const int g_max = 3;

template <class T>
class threadPool;

template <class T>
struct Context
{
    int _pos;
    threadPool<T>* _tp;
};

template <class T>
class threadPool
{
private:
    threadPool(int capacity = g_max)
    : _capacity(capacity)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < capacity; i++)
        {
            Context<T>* ct = new Context<T>;
            ct->_pos = i;
            ct->_tp = this;
            Thread* t = new Thread(handlerTask, ct);
            _threads.push_back(t);
        }
    }

    threadPool(const threadPool<T>&) = delete;

    threadPool<T>& operator=(const threadPool<T>&) = delete;

public:
    typedef function<void*(void*)> func;

    ~threadPool()
    {
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
        for (int i = 0; i < _capacity; i++)
        {
            delete _threads[i];
        }
    }

    static threadPool<T>* getInstance()
    {
        if (_tp == nullptr)
        {
            _glock->lock();
            if (_tp == nullptr)
            {
                _tp = new threadPool<T>;
                return _tp;
            }
            _glock->unlock();
        }
        return _tp;
    }

    static void* handlerTask(void* args)
    {
        Context<T>* ct = (Context<T>*)args;
        while (true)
        {
            T t;
            //获取任务
            ct->_tp->pop(&t);
            //处理任务
            cout << (ct->_tp->_threads[ct->_pos]->getThreadName()) << ": " << t() << endl;
        }
        delete ct;
        return nullptr;
    }

    void push(const T& in)
    {
        pthread_mutex_lock(&_lock);
        _taskqueue.push(in);
        pthread_cond_signal(&_cond);
        pthread_mutex_unlock(&_lock);
    }

    void pop(T* out)
    {
        pthread_mutex_lock(&_lock);
        while (_taskqueue.empty())
            pthread_cond_wait(&_cond, &_lock);
        *out = _taskqueue.front();
        _taskqueue.pop();
        pthread_mutex_unlock(&_lock);
    }

    void join()
    {
        for (int i = 0; i < _capacity; i++)
        {
            _threads[i]->join();
        }
    }

private:
    int _capacity;
    vector<Thread*> _threads;//把线程对象(指针)存起来主要是为了后续的join操作
    queue<T> _taskqueue;
    pthread_mutex_t _lock;
    pthread_cond_t _cond;
    static threadPool<T>* _tp;
    static mutex* _glock;
};
template <class T>
threadPool<T>* threadPool<T>::_tp = nullptr;
template <class T>
mutex* threadPool<T>::_glock = new mutex;